﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Windows.Forms.VisualStyles;
using System.ComponentModel;

namespace ListItemEditor.UI
{
    public class DataGridViewMultiSelectCell : DataGridViewTextBoxCell
    {
        public delegate object GetFormattedValueImpl(object value, int rowIndex, ref DataGridViewCellStyle cellStyle, TypeConverter valueTypeConverter, TypeConverter formattedValueTypeConverter, DataGridViewDataErrorContexts context);

        #region static variables
        [ThreadStatic]
        private static ComboBox _paintComboBox = new ComboBox();

        [ThreadStatic]
        private static Bitmap _renderingBitmap;

        public static GetFormattedValueImpl GlobalGetFormattedValue { get; set; }
        #endregion

        #region overrides

        public override Type EditType
        {
            get
            {
                // a dummy control
                return typeof (DataGridViewMultiSelectEditingControl);
            }
        }

        protected override void OnMouseClick(DataGridViewCellMouseEventArgs e)
        {
            base.OnMouseClick(e);

            if (e.Button != MouseButtons.Left) return;
            // test for shared row
            if (this.DataGridView == null || this.OwningRow.Index < 0) return;

            if (!this.IsInEditMode) return;

            DataGridViewMultiSelectEditingControl control = this.DataGridView.EditingControl as DataGridViewMultiSelectEditingControl;
            if (control == null) return;

            Point location = Control.MousePosition;
            location.Offset(-e.X, this.Size.Height - e.Y);

            control.OnCellMouseClick(this, location);
        }

        protected override Rectangle GetContentBounds(Graphics graphics, DataGridViewCellStyle cellStyle, int rowIndex)
        {
            // TODO - override this one properly - for the tooltip
            return base.GetContentBounds(graphics, cellStyle, rowIndex);
        }

        public override void PositionEditingControl(bool setLocation, bool setSize, Rectangle cellBounds, Rectangle cellClip, DataGridViewCellStyle cellStyle, bool singleVerticalBorderAdded, bool singleHorizontalBorderAdded, bool isFirstDisplayedColumn, bool isFirstDisplayedRow)
        {
            Rectangle newCellBounds = this.GetCorrectedTextBoundRect(cellBounds);
            base.PositionEditingControl(setLocation, setSize, newCellBounds, cellClip, cellStyle, singleVerticalBorderAdded, singleHorizontalBorderAdded, isFirstDisplayedColumn, isFirstDisplayedRow);
        }

        protected override object GetFormattedValue(object value, int rowIndex, ref DataGridViewCellStyle cellStyle, System.ComponentModel.TypeConverter valueTypeConverter, System.ComponentModel.TypeConverter formattedValueTypeConverter, DataGridViewDataErrorContexts context)
        {
            if (GlobalGetFormattedValue != null) return GlobalGetFormattedValue(value, rowIndex, ref cellStyle, valueTypeConverter, formattedValueTypeConverter, context);

            if (this.OwningColumn is DataGridViewMultiSelectColumn)
            {
                DataGridViewMultiSelectColumn column = this.OwningColumn as DataGridViewMultiSelectColumn;
                if (column.SelectedValuesTranslator != null) return column.SelectedValuesTranslator.FormatDisplayValue(value);
            }

            return base.GetFormattedValue(value, rowIndex, ref cellStyle, valueTypeConverter, formattedValueTypeConverter, context);
        }

        protected override void Paint(System.Drawing.Graphics graphics, System.Drawing.Rectangle clipBounds, System.Drawing.Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
        {
            // store the text value and paint the cell without it
            object originalFormattedValue = formattedValue;
            base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, "", errorText, cellStyle, advancedBorderStyle, paintParts);

            Rectangle dropDownButtonRect = this.GetDrowDownButtonRect(cellBounds);
            Rectangle textCellBounds = this.GetCorrectedTextBoundRect(cellBounds);
            // paint just the text value in the corrected text bounds
            base.Paint(graphics, clipBounds, textCellBounds, rowIndex, cellState, value, originalFormattedValue, errorText, cellStyle, advancedBorderStyle, DataGridViewPaintParts.ContentForeground);

            // paint the drop down button
            this.PaintDropDownButton(graphics, dropDownButtonRect);
        }

        #endregion

        #region private

        private Rectangle GetCorrectedTextBoundRect(Rectangle cellBounds)
        {
            Rectangle dropDownButtonRect = this.GetDrowDownButtonRect(cellBounds);
            return new Rectangle(cellBounds.Location, new Size(cellBounds.Width - dropDownButtonRect.Width - 3, cellBounds.Height));
        }

        private Rectangle GetDrowDownButtonRect(Rectangle cellBounds)
        {
            int height = Math.Max (Math.Min (cellBounds.Height - 5, 17), 0);
            int width = Math.Max (Math.Min(SystemInformation.HorizontalScrollBarThumbWidth, cellBounds.Width - 5), 0);
            Rectangle rect = new Rectangle(cellBounds.Right - width - 3, cellBounds.Top + 2, width, height);
            return rect;
        }

        private void PaintDropDownButton(Graphics graphics, Rectangle rect)
        {
            const int borderWidth = 2;
            const int borderWidth2 = borderWidth * 2;

            if (rect.Width <= 0 || rect.Height <= 0) return;

            // if we have this, the rendering of the drop down button is pretty easy, otherwise we need to do some ugly stuff
            if (VisualStyleRenderer.IsSupported)
            {
                ComboBoxRenderer.DrawDropDownButton(graphics, rect, System.Windows.Forms.VisualStyles.ComboBoxState.Normal);
            }
            else
            {
                if (_renderingBitmap == null)
                {
                    _renderingBitmap = new Bitmap(30, 30);
                }

                int bmpWidth = rect.Width + borderWidth * 2, bmpHeight = rect.Height + borderWidth * 2;
                _paintComboBox.Location = new Point(-100, -100);
                _paintComboBox.Width = bmpWidth;
                _paintComboBox.Height = bmpHeight;

                // Make sure the ComboBox control is parented to a visible control
                if (_paintComboBox.Parent == null || !_paintComboBox.Parent.Visible)
                {
                    _paintComboBox.Parent = this.DataGridView;
                }
                
                Rectangle srcRect = new Rectangle(0, 0, bmpWidth, bmpHeight);
                if (_renderingBitmap.Width < bmpWidth || _renderingBitmap.Height < bmpHeight)
                {
                    _renderingBitmap.Dispose();
                    _renderingBitmap = new Bitmap(bmpWidth, bmpHeight);
                }
                _paintComboBox.DrawToBitmap(_renderingBitmap, srcRect);
                _paintComboBox.Parent = null;

                if (srcRect.Width > borderWidth2 && srcRect.Height > borderWidth2)
                {
                    graphics.DrawImage(_renderingBitmap, rect,
                        new Rectangle(borderWidth, borderWidth, srcRect.Width - borderWidth2, srcRect.Height - borderWidth2), GraphicsUnit.Pixel);
                }
            }
        }

        #endregion

    }
}